/**
 * 网络请求优化器
 * 负责应用中网络请求的优化，包括缓存、重试、节流和并发控制
 */

import performanceConfig from '../config/performance.js';
import dataCache from './dataCache.js';
import { cacheStrategies } from './dataCache.js';
import { cacheUtils } from './dataCache.js';

class NetworkOptimizer {
  constructor() {
    this.config = performanceConfig;
    this.activeRequests = new Map(); // 活跃请求映射
    this.requestQueue = []; // 请求队列
    this.concurrentCount = 0; // 当前并发数
    this.setupRequestInterceptors();
  }
  
  /**
   * 设置请求拦截器
   */
  setupRequestInterceptors() {
    // 这里可以设置全局的请求拦截器
    // 在实际项目中，与uni.request集成
  }
  
  /**
   * 优化的网络请求方法
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  async request(options) {
    const { url, method = 'GET', data = {}, cache = true, ...rest } = options;
    
    // 获取缓存策略
    const cacheStrategy = cacheStrategies.getApiCacheStrategy(url, method);
    const useCache = cache && cacheStrategy.enabled && method === 'GET';
    
    // 生成缓存键
    const cacheKey = cacheUtils.createCacheKey(url, {
      method,
      data: this.normalizeData(data)
    });
    
    // 尝试从缓存获取
    if (useCache) {
      const cachedData = await dataCache.get(cacheKey, {
        useMemoryCache: true,
        useStorageCache: true
      });
      
      if (cachedData) {
        console.log(`[缓存命中] ${url}`);
        return this.createResponse(cachedData, true);
      }
    }
    
    // 检查是否有相同请求正在进行
    const requestId = this.getRequestId(url, method, data);
    if (this.activeRequests.has(requestId)) {
      console.log(`[请求合并] ${url}`);
      return this.activeRequests.get(requestId);
    }
    
    // 并发控制
    if (this.concurrentCount >= this.config.network.request.concurrentLimit) {
      console.log(`[请求排队] ${url}`);
      return this.queueRequest(options);
    }
    
    // 执行请求
    return this.executeRequest(options, requestId, cacheKey, cacheStrategy);
  }
  
  /**
   * 执行请求
   * @param {Object} options - 请求选项
   * @param {string} requestId - 请求ID
   * @param {string} cacheKey - 缓存键
   * @param {Object} cacheStrategy - 缓存策略
   * @returns {Promise} 请求结果
   */
  async executeRequest(options, requestId, cacheKey, cacheStrategy) {
    const { url, method = 'GET', data = {}, ...rest } = options;
    
    // 创建请求Promise
    const requestPromise = this.createRequestPromise(options, cacheKey, cacheStrategy);
    
    // 添加到活跃请求
    this.activeRequests.set(requestId, requestPromise);
    this.concurrentCount++;
    
    try {
      return await requestPromise;
    } finally {
      // 清理活跃请求
      this.activeRequests.delete(requestId);
      this.concurrentCount--;
      
      // 处理队列中的下一个请求
      this.processNextInQueue();
    }
  }
  
  /**
   * 创建请求Promise
   * @param {Object} options - 请求选项
   * @param {string} cacheKey - 缓存键
   * @param {Object} cacheStrategy - 缓存策略
   * @returns {Promise} 请求Promise
   */
  createRequestPromise(options, cacheKey, cacheStrategy) {
    const { url, method = 'GET', data = {}, timeout = this.config.network.request.timeout, ...rest } = options;
    
    // 使用重试机制
    return cacheUtils.retry(
      async () => {
        const startTime = Date.now();
        
        // 执行uni.request
        const response = await this.uniRequestWrapper({
          url,
          method,
          data,
          timeout,
          ...rest
        });
        
        const endTime = Date.now();
        const duration = endTime - startTime;
        
        // 记录请求性能
        this.recordRequestPerformance(url, method, duration, response.statusCode);
        
        // 缓存GET请求结果
        if (method === 'GET' && response.statusCode === 200 && cacheStrategy.enabled) {
          await dataCache.set(cacheKey, response.data, {
            cacheTime: cacheStrategy.cacheTime,
            storageType: cacheStrategy.storageType,
            compress: cacheStrategy.compress,
            encrypt: cacheStrategy.encrypt
          });
        }
        
        return response;
      },
      {
        retries: this.config.network.request.retryCount,
        delay: this.config.network.request.retryDelay,
        exponential: true
      }
    );
  }
  
  /**
   * uni.request包装器
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  uniRequestWrapper(options) {
    return new Promise((resolve, reject) => {
      // 添加默认header
      const headers = {
        'Content-Type': 'application/json',
        ...options.headers
      };
      
      // 执行请求
      uni.request({
        ...options,
        headers,
        success: (res) => {
          // 检查状态码
          if (res.statusCode >= 200 && res.statusCode < 300) {
            resolve(res);
          } else {
            reject(new Error(`请求失败: ${res.statusCode}`));
          }
        },
        fail: (err) => {
          // 记录失败请求
          if (this.config.monitor.network.recordFailedRequests) {
            this.recordFailedRequest(options, err);
          }
          reject(err);
        },
        complete: () => {
          // 可以在这里添加完成后的处理
        }
      });
    });
  }
  
  /**
   * 队列请求
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  queueRequest(options) {
    return new Promise((resolve, reject) => {
      this.requestQueue.push({
        options,
        resolve,
        reject
      });
    });
  }
  
  /**
   * 处理队列中的下一个请求
   */
  processNextInQueue() {
    if (this.requestQueue.length > 0 && this.concurrentCount < this.config.network.request.concurrentLimit) {
      const nextRequest = this.requestQueue.shift();
      this.request(options)
        .then(nextRequest.resolve)
        .catch(nextRequest.reject);
    }
  }
  
  /**
   * 生成请求ID
   * @param {string} url - 请求URL
   * @param {string} method - 请求方法
   * @param {Object} data - 请求数据
   * @returns {string} 请求ID
   */
  getRequestId(url, method, data) {
    return `${method}:${url}:${JSON.stringify(this.normalizeData(data))}`;
  }
  
  /**
   * 标准化数据
   * @param {Object} data - 原始数据
   * @returns {Object} 标准化后的数据
   */
  normalizeData(data) {
    if (typeof data !== 'object' || data === null) {
      return data;
    }
    
    // 对对象进行排序，确保相同内容生成相同的字符串
    const sortedData = {};
    Object.keys(data).sort().forEach(key => {
      sortedData[key] = data[key];
    });
    
    return sortedData;
  }
  
  /**
   * 记录请求性能
   * @param {string} url - 请求URL
   * @param {string} method - 请求方法
   * @param {number} duration - 持续时间
   * @param {number} statusCode - 状态码
   */
  recordRequestPerformance(url, method, duration, statusCode) {
    // 记录慢请求
    if (duration > this.config.monitor.network.slowRequestThreshold) {
      console.warn(`[慢请求警告] ${method} ${url} 耗时 ${duration}ms`);
      // 这里可以添加性能监控上报
    }
  }
  
  /**
   * 记录失败请求
   * @param {Object} options - 请求选项
   * @param {Error} error - 错误信息
   */
  recordFailedRequest(options, error) {
    // 简单的失败请求记录
    console.error(`[请求失败] ${options.method} ${options.url}:`, error);
    // 这里可以添加错误监控上报
  }
  
  /**
   * 创建响应对象
   * @param {any} data - 响应数据
   * @param {boolean} fromCache - 是否来自缓存
   * @returns {Object} 响应对象
   */
  createResponse(data, fromCache = false) {
    return {
      statusCode: 200,
      data,
      fromCache,
      headers: {
        'x-cache': fromCache ? 'HIT' : 'MISS'
      }
    };
  }
  
  /**
   * 预加载资源
   * @param {Array} resources - 资源列表
   * @returns {Promise} 预加载结果
   */
  async preloadResources(resources) {
    if (!this.config.network.prefetch.enabled) {
      return;
    }
    
    // 限制并发预加载数量
    const maxPrefetch = this.config.network.prefetch.maxPrefetchRequests;
    const batches = [];
    
    // 分割成批次
    for (let i = 0; i < resources.length; i += maxPrefetch) {
      batches.push(resources.slice(i, i + maxPrefetch));
    }
    
    // 逐个批次预加载
    for (const batch of batches) {
      await Promise.all(
        batch.map(resource => 
          this.request({
            url: resource.url,
            method: 'GET',
            cache: true,
            // 添加预加载标记
            headers: {
              'x-prefetch': 'true'
            }
          }).catch(err => {
            // 预加载失败不影响主流程
            console.warn(`预加载失败: ${resource.url}`, err);
          })
        )
      );
    }
  }
  
  /**
   * 取消请求
   * @param {string} url - 请求URL
   * @param {Object} options - 匹配选项
   * @returns {boolean} 是否取消成功
   */
  cancelRequest(url, options = {}) {
    const { method = 'ALL' } = options;
    let canceled = false;
    
    // 取消活跃请求
    for (const [requestId, promise] of this.activeRequests.entries()) {
      if (requestId.includes(url) && (method === 'ALL' || requestId.includes(method))) {
        // 在实际项目中，需要实现Promise的取消机制
        // 这里简化处理
        canceled = true;
      }
    }
    
    // 从队列中移除
    this.requestQueue = this.requestQueue.filter(req => {
      const shouldRemove = req.options.url === url && (method === 'ALL' || req.options.method === method);
      if (shouldRemove) {
        req.reject(new Error('请求已取消'));
        canceled = true;
      }
      return !shouldRemove;
    });
    
    return canceled;
  }
  
  /**
   * 取消所有请求
   */
  cancelAllRequests() {
    // 清空队列
    this.requestQueue.forEach(req => {
      req.reject(new Error('所有请求已取消'));
    });
    this.requestQueue = [];
    
    // 活跃请求需要实现取消机制
    console.log('所有队列中的请求已取消');
  }
  
  /**
   * 获取请求统计信息
   * @returns {Object} 统计信息
   */
  getRequestStats() {
    return {
      activeRequests: this.activeRequests.size,
      queuedRequests: this.requestQueue.length,
      concurrentCount: this.concurrentCount,
      maxConcurrent: this.config.network.request.concurrentLimit
    };
  }
  
  /**
   * 设置请求超时时间
   * @param {number} timeout - 超时时间（毫秒）
   */
  setDefaultTimeout(timeout) {
    this.config.network.request.timeout = timeout;
  }
  
  /**
   * 设置并发限制
   * @param {number} limit - 并发限制数
   */
  setConcurrentLimit(limit) {
    this.config.network.request.concurrentLimit = limit;
    
    // 重新检查队列
    this.processNextInQueue();
  }
  
  /**
   * 批量请求
   * @param {Array} requests - 请求数组
   * @param {Object} options - 批量选项
   * @returns {Promise<Array>} 结果数组
   */
  async batchRequests(requests, options = {}) {
    const { 
      batchSize = 5,
      interval = 0,
      failFast = false
    } = options;
    
    const results = [];
    
    for (let i = 0; i < requests.length; i += batchSize) {
      const batch = requests.slice(i, i + batchSize);
      
      if (failFast) {
        // 快速失败模式
        const batchResults = await Promise.all(
          batch.map(req => this.request(req))
        );
        results.push(...batchResults);
      } else {
        // 允许部分失败
        const batchPromises = batch.map(req => 
          this.request(req)
            .then(data => ({ success: true, data }))
            .catch(err => ({ success: false, error: err }))
        );
        
        const batchResults = await Promise.all(batchPromises);
        results.push(...batchResults);
      }
      
      // 添加间隔
      if (interval > 0 && i + batchSize < requests.length) {
        await new Promise(resolve => setTimeout(resolve, interval));
      }
    }
    
    return results;
  }
}

// 导出单例
const networkOptimizer = new NetworkOptimizer();
export default networkOptimizer;

// 导出优化后的请求方法
export const request = networkOptimizer.request.bind(networkOptimizer);
export const preload = networkOptimizer.preloadResources.bind(networkOptimizer);
export const cancelRequest = networkOptimizer.cancelRequest.bind(networkOptimizer);
export const cancelAllRequests = networkOptimizer.cancelAllRequests.bind(networkOptimizer);
export const batchRequests = networkOptimizer.batchRequests.bind(networkOptimizer);

// 导出便捷方法
export const http = {
  /**
   * GET请求
   * @param {string} url - 请求URL
   * @param {Object} params - 请求参数
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  get(url, params = {}, options = {}) {
    return request({
      url,
      method: 'GET',
      data: params,
      ...options
    });
  },
  
  /**
   * POST请求
   * @param {string} url - 请求URL
   * @param {Object} data - 请求数据
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  post(url, data = {}, options = {}) {
    return request({
      url,
      method: 'POST',
      data,
      ...options
    });
  },
  
  /**
   * PUT请求
   * @param {string} url - 请求URL
   * @param {Object} data - 请求数据
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  put(url, data = {}, options = {}) {
    return request({
      url,
      method: 'PUT',
      data,
      ...options
    });
  },
  
  /**
   * DELETE请求
   * @param {string} url - 请求URL
   * @param {Object} params - 请求参数
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  delete(url, params = {}, options = {}) {
    return request({
      url,
      method: 'DELETE',
      data: params,
      ...options
    });
  },
  
  /**
   * 上传文件
   * @param {string} url - 请求URL
   * @param {Object} file - 文件对象
   * @param {Object} data - 其他数据
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  upload(url, file, data = {}, options = {}) {
    const { onProgressUpdate, ...rest } = options;
    
    return new Promise((resolve, reject) => {
      uni.uploadFile({
        url,
        filePath: file.path,
        name: file.name || 'file',
        formData: data,
        onProgressUpdate,
        success: resolve,
        fail: reject,
        ...rest
      });
    });
  },
  
  /**
   * 下载文件
   * @param {string} url - 文件URL
   * @param {Object} options - 请求选项
   * @returns {Promise} 下载结果
   */
  download(url, options = {}) {
    const { onProgressUpdate, ...rest } = options;
    
    return new Promise((resolve, reject) => {
      uni.downloadFile({
        url,
        onProgressUpdate,
        success: resolve,
        fail: reject,
        ...rest
      });
    });
  }
};

// 导出网络状态工具
export const networkUtils = {
  /**
   * 检查网络连接
   * @returns {Promise<Object>} 网络状态
   */
  async checkNetworkStatus() {
    return new Promise((resolve) => {
      uni.getNetworkType({
        success: resolve
      });
    });
  },
  
  /**
   * 监听网络变化
   * @param {Function} callback - 回调函数
   * @returns {Object} 监听器对象
   */
  onNetworkChange(callback) {
    uni.onNetworkStatusChange(callback);
    
    // 返回取消监听的方法
    return {
      off: () => uni.offNetworkStatusChange(callback)
    };
  },
  
  /**
   * 是否在线
   * @returns {Promise<boolean>} 是否在线
   */
  async isOnline() {
    const networkType = await this.checkNetworkStatus();
    return networkType.networkType !== 'none';
  },
  
  /**
   * 是否是WiFi
   * @returns {Promise<boolean>} 是否是WiFi
   */
  async isWifi() {
    const networkType = await this.checkNetworkStatus();
    return networkType.networkType === 'wifi';
  },
  
  /**
   * 获取网络类型
   * @returns {Promise<string>} 网络类型
   */
  async getNetworkType() {
    const networkType = await this.checkNetworkStatus();
    return networkType.networkType;
  }
};

// 导出网络优化建议
export const networkOptimizationTips = {
  /**
   * 获取请求优化建议
   * @param {Object} requestInfo - 请求信息
   * @returns {Array<string>} 优化建议
   */
  getRequestOptimizationTips(requestInfo) {
    const tips = [];
    
    if (requestInfo.duration > 3000) {
      tips.push('请求响应时间过长，建议优化API性能或增加缓存');
    }
    
    if (requestInfo.size > 1024 * 1024) { // 大于1MB
      tips.push('响应数据过大，建议分页加载或减少返回字段');
    }
    
    if (requestInfo.frequency > 10) { // 每秒超过10次
      tips.push('请求频率过高，建议合并请求或增加缓存时间');
    }
    
    return tips;
  },
  
  /**
   * 获取批量请求策略
   * @param {number} totalRequests - 总请求数
   * @returns {Object} 批量策略
   */
  getBatchRequestStrategy(totalRequests) {
    if (totalRequests <= 5) {
      return { batchSize: totalRequests, interval: 0 };
    } else if (totalRequests <= 20) {
      return { batchSize: 5, interval: 100 };
    } else if (totalRequests <= 100) {
      return { batchSize: 10, interval: 200 };
    } else {
      return { batchSize: 20, interval: 500 };
    }
  }
};